package org.bean;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Analyzer {
    public Analyzer() {
    }

    public  enum TokenType {
        ADD,
        SUB,
        MUL,
        DIV,
        LPAREN,
        RPAREN,
        id,
        END
    }
    List<Token> tokenList;

     public static class Token {
        TokenType type;
        String value;

         public Token(TokenType tokenType, String tokenText) {
            this.type=tokenType;
            this.value=tokenText;
         }
         @Override
         public String toString(){
             return type+"\n"+value;
         }
     }


    private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+");
    private static final Pattern ID = Pattern.compile("([a-zA-Z]+[0-9]*)+");
    private static final Pattern END = Pattern.compile("\\$");

    private static final Pattern ADD = Pattern.compile("[+]");
    private static final Pattern SUB = Pattern.compile("-");
    private static final Pattern MUL = Pattern.compile("[*]");
    private static final Pattern DIV = Pattern.compile("/");
    private static final Pattern LPAREN_PATTERN = Pattern.compile("\\(");
    private static final Pattern RPAREN_PATTERN = Pattern.compile("\\)");

    /**
     * 简单的词法分析
     * @param expression
     * @return
     */
    public List<Token> lex(String expression) {
        List<Token> tokens = new ArrayList<>();
        while (!expression.isEmpty()) {
            Matcher matcher ;
            if ((matcher = NUMBER_PATTERN.matcher(expression)).lookingAt()) {
                String value = matcher.group();
                tokens.add(new Token(TokenType.id, value));
            }
            else if ((matcher = END.matcher(expression)).lookingAt()) {
                String value = matcher.group();
                tokens.add(new Token(TokenType.END, value));
            }
            else if ((matcher = ID.matcher(expression)).lookingAt()) {
                String value = matcher.group();
                tokens.add(new Token(TokenType.id, value));
            } else if ((matcher = ADD.matcher(expression)).lookingAt()) {
                String value = matcher.group();
                tokens.add(new Token(TokenType.ADD, value));
            } else if ((matcher = SUB.matcher(expression)).lookingAt()) {
                String value = matcher.group();
                tokens.add(new Token(TokenType.SUB, value));
            } else if ((matcher = DIV.matcher(expression)).lookingAt()) {
                String value = matcher.group();
                tokens.add(new Token(TokenType.DIV, value));
            } else if ((matcher = MUL.matcher(expression)).lookingAt()) {
                    String value = matcher.group();
                    tokens.add(new Token(TokenType.MUL, value));
            } else if ((matcher = LPAREN_PATTERN.matcher(expression)).lookingAt()) {
                String value = matcher.group();
                tokens.add(new Token(TokenType.LPAREN, value));
            } else if ((matcher = RPAREN_PATTERN.matcher(expression)).lookingAt()) {
                String value = matcher.group();
                tokens.add(new Token(TokenType.RPAREN, value));
            }else {
                throw new RuntimeException("Invalid token: " + expression.charAt(0));
            }
            expression = expression.substring(matcher.end());
        }
        return tokens;
    }

    public Analyzer(String programText, List<ActionTable> actionTables, CopyOnWriteArrayList<CopyOnWriteArraySet<SLRProduction>> items, List<String> productions){
        super();
        this.actionTableList=actionTables;
        this.programText=programText;
        this.items=items;
        this.slrList =productions;
        actionTableMap=new HashMap<>();
        for (ActionTable actionTable : actionTableList) {
            String index = actionTable.getIndex();
            actionTableMap.put(index,actionTable);
        };
        itemMap=new HashMap<>();
        int i=0;
        for (CopyOnWriteArraySet<SLRProduction> item : items) {
            itemMap.put(i,item);
            i++;
        }
    }
    public List<ActionTable> actionTableList;//分析表

    public List<String> slrList;

    public String programText;//待分析句子

    public CopyOnWriteArrayList<CopyOnWriteArraySet<SLRProduction>> items;//状态集


    public Map<String,ActionTable> actionTableMap;//分析表映射

    public Map<Integer,CopyOnWriteArraySet<SLRProduction>> itemMap;


    /*
    算法3.3 LR 分析算法。
    输入输入串w和文法G的LR分析表。
    输出若w∈L(G),则输出w自下而上分析的归约步骤,否则报错。
    方法分析器 初始情况是:初始状态so在分析器的栈顶,w$在输人缓冲区。然后分析器执行图3.12的程序。
    令a是w$的第一个符号;
    while(1)
    {
        令s是栈定状态
    if (action[s, a] ==移进t ) |
        把a和t依次压人栈;
        令a是下一个输人符号;
    | else if (action[s, a] ==归约A→β) {
            栈顶退掉2 * |β| 个符号;//这里其实是推掉符号栈和状态栈
            令t是现在的栈顶状态;
            把A和goto[t, A]压人栈;
            输出产生式A→β;
    | else if (action[s, a] ==接受) break;
            else调用错误恢复例程;
        }
    }
     */

    public  boolean analyze() {
        tokenList=lex(programText);
        for (Token token : tokenList) {
            System.out.println(token);
        }
        System.out.println("开始进行分析");

        boolean topIsItem=true;//定义栈顶是否是状态

        int index=0;
        //先不考虑此法分析器
        Stack<Object> stack=new Stack<>();
        stack.push(0);//另栈定是初始状态
        while(!stack.isEmpty()){
            //输出栈的内容
            Object[] array = stack.toArray();
            StringBuilder strBuilder = new StringBuilder();
            for (Object o : array) {
                if(o instanceof String){
                    strBuilder.append((String)o);
                }
                else {
                    strBuilder.append(((Integer)o).toString());
                }
            };
            System.out.format("%-40s", strBuilder.toString());
            System.out.format("%-40s", programText.substring(index));
            String s = String.valueOf(programText.charAt(index));
            if(s.equals("1"))s="id";
            Object I=stack.peek();
            if(I instanceof String) s= (String)stack.peek();
            String indexStr= null;
            if (I instanceof Integer) {
                indexStr = items.indexOf(itemMap.get((Integer) I))+"," + s;
                ActionTable actionTable = actionTableMap.get(indexStr);//得到分析表
                if(actionTable.act.contains("s")){
                    System.out.format("%-20s\n", "|使用"+actionTable.act+"移进");
                    //移进输入
                    stack.push(s);
                    itemMap.get(Integer.parseInt(String.valueOf(actionTable.act.charAt(1))));
                    stack.push(Integer.parseInt(String.valueOf(actionTable.act.substring(1))));
                    index=index+1;
                }
                else if(actionTable.act.contains("r")){
                    //归约
                    //先弹出栈顶状态
                    int r=Integer.parseInt(String.valueOf(actionTable.act.charAt(1)));//得到归约项
                    String production = slrList.get(r);
                    String s2="|使用"+production+"规约";
                    System.out.format("%-20s\n",s2);
                    String[] split = production.split("->");
                    List<String> slrRight= new ArrayList<>(Arrays.asList(split));
                    String left=slrRight.get(0);//规约项左部
                    slrRight.remove(0);
                    //弹出栈定归约项右部
                    String tst=slrRight.get(0).replace("id","a");
                    int len=tst.length();
                    Stack<String> tmp=new Stack<>();
                    for(int i=0;i<len;i++){
                        stack.pop();
                        stack.pop();
//                        tmp.push(string);
                    };
                    //入栈规约项左部
                    stack.push(left);
                    StringBuilder str=new StringBuilder();
                }
                else {
                    //接受
                    String s3="|接受";
                    System.out.format("%-20s\n", s3);
                    System.out.println("匹配成功");
                    break;
                }
            }
            else {
                //栈顶是符号
                //要进行跳转
//                System.out.println();
                    String str = (String)stack.pop();
                    Object pop = stack.peek();
                    stack.push(str);
                    if(pop instanceof String){
                        break;
                    }
                    ActionTable actionTable = actionTableMap.get((Integer)pop + "," + str);
                    if(actionTable==null){
                        System.out.println("error匹配失败");
                        return false;
                    }
                    else{
                        //这里不能直接取索引为0的字符，因为可能跳转的状态是两位数的
//                        stack.push(Integer.parseInt(String.valueOf(actionTable.act.charAt(0))));
                        System.out.format("|%-20s\n","跳转到状态"+actionTable.act);
                        stack.push(Integer.parseInt(String.valueOf(actionTable.act)));
                }
            }
            if(index==programText.length()&&stack.size()>1){
                return false;
            }
        };
        return true;
    }


    /**
     * 带词法分析的语法分析
     * @return boolean
     */
    public  boolean analyzeWithLex() throws Exception {
        tokenList=lex(programText);
        System.out.println("开始进行分析");
        int index=0;
        //先不考虑此法分析器
        Stack<Object> stack=new Stack<>();
        stack.push(0);//另栈定是初始状态
        while(!stack.isEmpty()){
            //输出栈的内容
            Object[] array = stack.toArray();
            StringBuilder strBuilder = new StringBuilder();
            for (Object o : array) {
                if(o instanceof String){
                    strBuilder.append((String)o);
                }
                else {
                    strBuilder.append(((Integer)o).toString());
                }
            };
            System.out.format("%-40s", strBuilder.toString());
            strBuilder=new StringBuilder();
            for(int j=index;j<tokenList.size();j++){
                strBuilder.append(tokenList.get(j).value);
            }
            System.out.format("%-40s", strBuilder);
            Token token = tokenList.get(index);
            String s = token.value;
            if(token.type==TokenType.id)
                s=token.type.name();//赋值为id
            Object I=stack.peek();
            if(I instanceof String) s= (String)stack.peek();
            String indexStr= null;
            if (I instanceof Integer) {
                try {
                    indexStr = items.indexOf(itemMap.get((Integer) I)) + "," + s;
                    ActionTable actionTable = actionTableMap.get(indexStr);//得到分析表
                    if (actionTable.act.contains("s")) {
                        System.out.format("%-20s\n", "|使用" + actionTable.act + "移进");
                        //移进输入
                        stack.push(s);
                        itemMap.get(Integer.parseInt(String.valueOf(actionTable.act.charAt(1))));
                        stack.push(Integer.parseInt(String.valueOf(actionTable.act.substring(1))));
                        index = index + 1;
                    } else if (actionTable.act.contains("r")) {
                        //归约
                        //先弹出栈顶状态
                        int r = Integer.parseInt(String.valueOf(actionTable.act.charAt(1)));//得到归约项
                        String production = slrList.get(r);
                        String s2 = "|使用" + production + "规约";
                        System.out.format("%-20s\n", s2);
                        String[] split = production.split("->");
                        List<String> slrRight = new ArrayList<>(Arrays.asList(split));
                        String left = slrRight.get(0);//规约项左部
                        slrRight.remove(0);
                        //弹出栈定归约项右部
                        String tst = slrRight.get(0).replace("id", "a");
                        int len = tst.length();
                        Stack<String> tmp = new Stack<>();
                        for (int i = 0; i < len; i++) {
                            stack.pop();
                            stack.pop();
//                        tmp.push(string);
                        }
                        ;
                        //入栈规约项左部
                        stack.push(left);
                        StringBuilder str = new StringBuilder();
                    } else {
                        //接受
                        String s3 = "|接受";
                        System.out.format("%-20s\n", s3);
                        System.out.println("匹配成功");
                        break;
                    }
                }
                catch (Exception e){
                    throw new Exception("匹配失败， 该句子不符合SLR文法");
//                    return false;
                }
            }
            else {
                //栈顶是符号
                //要进行跳转
//                System.out.println();
                String str = (String)stack.pop();
                Object pop = stack.peek();
                stack.push(str);
                if(pop instanceof String){
                    break;
                }
                ActionTable actionTable = actionTableMap.get((Integer)pop + "," + str);
                if(actionTable==null){
                    System.out.println("error匹配失败");
                    return false;
                }
                else{
                    //这里不能直接取索引为0的字符，因为可能跳转的状态是两位数的
//                        stack.push(Integer.parseInt(String.valueOf(actionTable.act.charAt(0))));
                    System.out.format("|%-20s\n","跳转到状态"+actionTable.act);
                    stack.push(Integer.parseInt(String.valueOf(actionTable.act)));
                }
            }
            if(index==programText.length()&&stack.size()>1){
                return false;
            }
        };
        return true;
    }
    /*
                问题记录
                List<String> slrRight= new ArrayList<>(Arrays.asList(split));
                会抛出UnsupportedOperationException
                这是为什么呢？因为我习惯性以为Arrays.asList返回的是一个java.util.ArrayList但实际上并不是，
                从asList的源码可以看到返回的实际上是一个静态内部类ArrayList<E>，而该类虽然继承了AbstractList，
                但是并没有Override抽象类中关于新增、删除的方法，因此才会抛出UnsupportedOperationException异常。

                 */

}
